"""
日期工具类，提供日期格式转换、日期加减、年龄计算和随机日期生成等功能
"""

import datetime
import random
from typing import Union, Optional


class DateUtils:
    """
    日期工具类，提供各种日期处理功能
    """
    
    @staticmethod
    def parse_date(date_str: str, format_str: str = "%Y-%m-%d") -> datetime.datetime:
        """
        解析日期字符串为datetime对象

        :param date_str: 日期字符串
        :param format_str: 日期格式字符串
        :return: datetime对象
        """
        return datetime.datetime.strptime(date_str, format_str)
    
    @staticmethod
    def format_date(date_obj: Union[datetime.datetime, datetime.date], format_str: str = "%Y-%m-%d") -> str:
        """
        将datetime对象格式化为字符串

        :param date_obj: datetime对象
        :param format_str: 目标日期格式字符串
        :return: 格式化后的日期字符串
        """
        return date_obj.strftime(format_str)
    
    @staticmethod
    def convert_date_format(date_str: str, from_format: str, to_format: str) -> str:
        """
        转换日期字符串的格式

        :param date_str: 原始日期字符串
        :param from_format: 原始日期格式
        :param to_format: 目标日期格式
        :return: 转换后的日期字符串
        """
        date_obj = DateUtils.parse_date(date_str, from_format)
        return DateUtils.format_date(date_obj, to_format)
    
    @staticmethod
    def add_years(date_obj: Union[datetime.datetime, datetime.date], years: int) -> datetime.datetime:
        """
        给日期增加年份

        :param date_obj: 原始日期
        :param years: 要增加的年数（可为负数表示减少）
        :return: 计算后的日期
        """
        try:
            return date_obj.replace(year=date_obj.year + years)
        except ValueError:
            # 处理闰年2月29日的特殊情况
            return date_obj.replace(year=date_obj.year + years, day=date_obj.day - 1)
    
    @staticmethod
    def add_months(date_obj: Union[datetime.datetime, datetime.date], months: int) -> datetime.datetime:
        """
        给日期增加月份

        :param date_obj: 原始日期
        :param months: 要增加的月数（可为负数表示减少）
        :return: 计算后的日期
        """
        # 计算新的年份和月份
        new_month = date_obj.month + months
        new_year = date_obj.year + (new_month - 1) // 12
        new_month = ((new_month - 1) % 12) + 1
        
        # 处理日期溢出情况（例如1月31日加1个月应该是2月28日或29日）
        try:
            return date_obj.replace(year=new_year, month=new_month)
        except ValueError:
            # 如果日期不存在，则回退到该月的最后一天
            if new_month == 12:
                next_month = date_obj.replace(year=new_year+1, month=1, day=1)
            else:
                next_month = date_obj.replace(year=new_year, month=new_month+1, day=1)
            return next_month - datetime.timedelta(days=1)
    
    @staticmethod
    def add_days(date_obj: Union[datetime.datetime, datetime.date], days: int) -> datetime.datetime:
        """
        给日期增加天数

        :param date_obj: 原始日期
        :param days: 要增加的天数（可为负数表示减少）
        :return: 计算后的日期
        """
        return date_obj + datetime.timedelta(days=days)
    
    @staticmethod
    def add_hours(date_obj: Union[datetime.datetime, datetime.date], hours: int) -> datetime.datetime:
        """
        给日期增加小时数

        :param date_obj: 原始日期
        :param hours: 要增加的小时数（可为负数表示减少）
        :return: 计算后的日期
        """
        return date_obj + datetime.timedelta(hours=hours)
    
    @staticmethod
    def add_minutes(date_obj: Union[datetime.datetime, datetime.date], minutes: int) -> datetime.datetime:
        """
        给日期增加分钟数

        :param date_obj: 原始日期
        :param minutes: 要增加的分钟数（可为负数表示减少）
        :return: 计算后的日期
        """
        return date_obj + datetime.timedelta(minutes=minutes)
    
    @staticmethod
    def add_seconds(date_obj: Union[datetime.datetime, datetime.date], seconds: int) -> datetime.datetime:
        """
        给日期增加秒数

        :param date_obj: 原始日期
        :param seconds: 要增加的秒数（可为负数表示减少）
        :return: 计算后的日期
        """
        return date_obj + datetime.timedelta(seconds=seconds)
    
    @staticmethod
    def calculate_age(birth_date: Union[datetime.datetime, datetime.date], 
                     current_date: Optional[Union[datetime.datetime, datetime.date]] = None) -> int:
        """
        计算周岁年龄

        :param birth_date: 出生日期
        :param current_date: 当前日期，默认为今天
        :return: 周岁年龄
        """
        if current_date is None:
            current_date = datetime.date.today()
        
        # 确保比较的是日期部分
        if isinstance(birth_date, datetime.datetime):
            birth_date = birth_date.date()
        if isinstance(current_date, datetime.datetime):
            current_date = current_date.date()
        
        # 计算年龄
        age = current_date.year - birth_date.year
        
        # 检查是否还没过生日
        if (current_date.month, current_date.day) < (birth_date.month, birth_date.day):
            age -= 1
            
        return age
    
    @staticmethod
    def add_age(birth_date: Union[datetime.datetime, datetime.date], 
               age: int) -> datetime.date:
        """
        根据出生日期和年龄计算目标日期

        :param birth_date: 出生日期
        :param age: 年龄
        :return: 目标日期
        """
        # 确保比较的是日期部分
        if isinstance(birth_date, datetime.datetime):
            birth_date = birth_date.date()
        
        # 计算目标年份
        target_year = birth_date.year + age
            
        # 计算目标日期
        try:
            return birth_date.replace(year=target_year)
        except ValueError:
            # 处理闰年2月29日的特殊情况
            return birth_date.replace(year=target_year, day=birth_date.day - 1)
    
    @staticmethod
    def random_date(start_date: Union[datetime.datetime, datetime.date], 
                   end_date: Union[datetime.datetime, datetime.date]) -> datetime.datetime:
        """
        在指定日期范围内随机生成一个日期

        :param start_date: 开始日期
        :param end_date: 结束日期
        :return: 随机生成的日期
        """
        # 确保比较的是日期部分
        if isinstance(start_date, datetime.datetime):
            start_date = start_date.date()
        if isinstance(end_date, datetime.datetime):
            end_date = end_date.date()
            
        # 计算日期差
        time_between = end_date - start_date
        days_between = time_between.days
        
        # 随机选择天数
        random_days = random.randint(0, days_between)
        
        # 生成随机日期
        random_date = start_date + datetime.timedelta(days=random_days)
        
        # 添加随机的时间部分
        random_hour = random.randint(0, 23)
        random_minute = random.randint(0, 59)
        random_second = random.randint(0, 59)
        
        return datetime.datetime(
            random_date.year, 
            random_date.month, 
            random_date.day,
            random_hour,
            random_minute,
            random_second
        )
    
    @staticmethod
    def random_date_with_format(start_date_str: str, 
                               end_date_str: str, 
                               date_format: str = "%Y-%m-%d") -> str:
        """
        在指定日期范围内随机生成一个日期并按指定格式返回

        :param start_date_str: 开始日期字符串
        :param end_date_str: 结束日期字符串
        :param date_format: 日期格式
        :return: 随机生成的日期字符串
        """
        start_date = DateUtils.parse_date(start_date_str, date_format)
        end_date = DateUtils.parse_date(end_date_str, date_format)
        random_date = DateUtils.random_date(start_date, end_date)
        return DateUtils.format_date(random_date, date_format)